/***************************************************************
 *  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
 *  All rights reserved
 *
 *  This file is part of the GroupMe! Project. You can utilize
 *  software of the GroupMe! project under the terms of the 
 *  GNU Lesser General Public License as published by the
 *  Free Software Foundation in version 2.1.
 * 
 *  The GNU Lesser General Public License can be found at:
 *  http://www.gnu.org/licenses/lgpl.html
 *
 *  This copyright notice MUST APPEAR in all copies of the file!
 ***************************************************************/
package net.groupme.model.dao;

import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Types;

import javax.sql.DataSource;

import net.groupme.exceptions.InsertFailedException;
import net.groupme.exceptions.UpdateFailedException;
import net.groupme.model.GroupVisualization;
import net.groupme.model.GroupVisualizationImpl;
import net.groupme.model.Resource;
import net.groupme.model.ResourceImpl;
import net.groupme.utils.sql.GetIntFromTableWhereIDQuery;
import net.groupme.utils.sql.GetStringFromTableWhereIDQuery;
import net.groupme.utils.sql.GetStringQuery;
import net.groupme.utils.sql.SQLUpdateUtility;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.SqlUpdate;
import org.springframework.jdbc.support.GeneratedKeyHolder;

/**
 * 
 * This class provides... This interface defines...
 * 
 * @author Mischa Frank <a
 *         href="mailto:code@planetfrank.net">code@planetfrank.net</a>
 * 
 * @version 1.0, created on 30.04.2007
 * 
 */
public class ResourceVisualizationDAOImpl implements ResourceVisualizationDAO {

	// table
	private static final String TABLE_RESOURCEVISUALIZATION = DBProperties
			.getString("GroupmeDB.TABLE_RESOURCEVISUALIZATION"); //$NON-NLS-1$

	// columns
	private static final String RESOURCEVISUALIZATION_ID = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_ID"); //$NON-NLS-1$

	private static final String RESOURCEVISUALIZATION_VISUALIZATIONID = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_VISUALIZATIONID"); //$NON-NLS-1$

	private static final String RESOURCEVISUALIZATION_RESOURCEID = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_RESOURCEID"); //$NON-NLS-1$

	private static final String RESOURCEVISUALIZATION_POSITIONX = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_POSITIONX"); //$NON-NLS-1$

	private static final String RESOURCEVISUALIZATION_POSITIONY = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_POSITIONY"); //$NON-NLS-1$

	private static final String RESOURCEVISUALIZATION_WIDTH = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_WIDTH"); //$NON-NLS-1$

	private static final String RESOURCEVISUALIZATION_HEIGHT = DBProperties
			.getString("GroupmeDB.RESOURCEVISUALIZATION_HEIGHT"); //$NON-NLS-1$
	
	private static final String RESOURCEVISUALIZATION_POSITIONZ = DBProperties
	.getString("GroupmeDB.RESOURCEVISUALIZATION_POSITIONZ"); //$NON-NLS-1$
	
	/** column name of the rendering indicator (field where we insert the name of the bean which renders this object */
	private static final String RESOURCEVISUALIZATION_RENDERER = DBProperties
	.getString("GroupmeDB.ResourceVisualization.renderingClass"); //$NON-NLS-1$

	private static final Logger log = Logger
			.getLogger(ResourceVisualizationDAOImpl.class);

	private DataSource ds;

	private String id;

	private String query;

	public ResourceVisualizationDAOImpl(DataSource ds, String id) {
		this.ds = ds;
		this.id = id;
	}

	public ResourceVisualizationDAOImpl(DataSource ds,
			String groupVisualizationID, String resourceId, int posX, int posY,
			int width, int height, int zAxis, String rendererID) throws InsertFailedException {
		this.ds = ds;
		SqlUpdate su = new SqlUpdate(ds, "INSERT INTO " + TABLE_RESOURCEVISUALIZATION//$NON-NLS-1$
				+ " (" + RESOURCEVISUALIZATION_VISUALIZATIONID + ", " 
				+ RESOURCEVISUALIZATION_RESOURCEID + ", "
				+ RESOURCEVISUALIZATION_POSITIONX + ", " 
				+ RESOURCEVISUALIZATION_POSITIONY + ", "
				+ RESOURCEVISUALIZATION_WIDTH + ", " 
				+ RESOURCEVISUALIZATION_HEIGHT + ", "
				+ RESOURCEVISUALIZATION_POSITIONZ + ", " 
				+ RESOURCEVISUALIZATION_RENDERER + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
		su.declareParameter(new SqlParameter("visuID", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("resID", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("posX", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("posY", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("width", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("height", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("zAxis", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("renderer", Types.VARCHAR)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[8];
		oa[0] = new Integer(groupVisualizationID);
		oa[1] = new Integer(resourceId);
		oa[2] = new Integer(posX);
		oa[3] = new Integer(posY);
		oa[4] = new Integer(width);
		oa[5] = new Integer(height);
		oa[6] = new Integer(zAxis);
		oa[7] = rendererID;
		GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
		int count = su.update(oa, keyHolder);
		if (count == 0)
			throw new InsertFailedException();
		this.id = keyHolder.getKey().toString();
	}

	/* (non-Javadoc)
	 * @see net.groupme.model.Identifiable#getId()
	 */
	public String getId() {
		return this.id;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getDescription()
	 */
	public String getDescription() {
		return this.getLabel() + " position(" + this.getPositionX() + ", "
				+ this.getPositionY() + ") size(" + this.getWidth() + ", "
				+ this.getHeight() + ")";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getGroupVisualization()
	 */
	public GroupVisualization getGroupVisualization() {
		query = "SELECT " + RESOURCEVISUALIZATION_VISUALIZATIONID + " FROM " + TABLE_RESOURCEVISUALIZATION//$NON-NLS-1$ //$NON-NLS-2$
				+ " WHERE " + RESOURCEVISUALIZATION_ID + " = " + id; //$NON-NLS-1$ //$NON-NLS-2$
		GetStringQuery getStringQuery = new GetStringQuery(ds, query,
				RESOURCEVISUALIZATION_VISUALIZATIONID);
		GroupVisualization visualization = new GroupVisualizationImpl(
				new GroupVisualizationDAOImpl(ds, (String) getStringQuery
						.execute().iterator().next()));
		return visualization;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getHeight()
	 */
	public int getHeight() {
		GetIntFromTableWhereIDQuery getHeightQuery = new GetIntFromTableWhereIDQuery(
				ds, RESOURCEVISUALIZATION_HEIGHT, TABLE_RESOURCEVISUALIZATION,
				id);
		return (Integer) getHeightQuery.execute().iterator().next();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getLabel()
	 */
	public String getLabel() {
		return "Visualization of Resource: " + this.getResource().getLabel();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getPositionX()
	 */
	public int getPositionX() {
		GetIntFromTableWhereIDQuery getPosXQuery = new GetIntFromTableWhereIDQuery(
				ds, RESOURCEVISUALIZATION_POSITIONX,
				TABLE_RESOURCEVISUALIZATION, id);
		return (Integer) getPosXQuery.execute().iterator().next();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getPositionY()
	 */
	public int getPositionY() {
		GetIntFromTableWhereIDQuery getPosYQuery = new GetIntFromTableWhereIDQuery(
				ds, RESOURCEVISUALIZATION_POSITIONY,
				TABLE_RESOURCEVISUALIZATION, id);
		return (Integer) getPosYQuery.execute().iterator().next();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getRenderer()
	 */
	public String getRenderer() {
		return (String) new GetStringFromTableWhereIDQuery(
				ds, RESOURCEVISUALIZATION_RENDERER, TABLE_RESOURCEVISUALIZATION, id).execute().iterator().next();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getResource()
	 */
	public Resource getResource() {
		query = "SELECT " + RESOURCEVISUALIZATION_RESOURCEID + " FROM " + TABLE_RESOURCEVISUALIZATION//$NON-NLS-1$ //$NON-NLS-2$
				+ " WHERE " + RESOURCEVISUALIZATION_ID + " = " + id; //$NON-NLS-1$ //$NON-NLS-2$
		GetStringQuery getStringQuery = new GetStringQuery(ds, query,
				RESOURCEVISUALIZATION_RESOURCEID);
		Resource resource = new ResourceImpl(new ResourceDAOImpl(ds,
				(String) getStringQuery.execute().iterator().next()));
		return resource;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getURI()
	 */
	public URI getURI(){
		try {
			return new URI("http://www.groupme.net/resourcevisualization/" + id);//$NON-NLS-1$
		} catch (URISyntaxException e) {
			e.printStackTrace();
			return null;
		} 
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getWidth()
	 */
	public int getWidth() {
		GetIntFromTableWhereIDQuery getWidthQuery = new GetIntFromTableWhereIDQuery(
				ds, RESOURCEVISUALIZATION_WIDTH, TABLE_RESOURCEVISUALIZATION,
				id);
		return (Integer) getWidthQuery.execute().iterator().next();
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#getZAxis()
	 */
	public int getZAxis() {
		GetIntFromTableWhereIDQuery getZAxisQuery = new GetIntFromTableWhereIDQuery(
				ds, RESOURCEVISUALIZATION_POSITIONZ, TABLE_RESOURCEVISUALIZATION,
				id);
		return (Integer) getZAxisQuery.execute().iterator().next();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#setDescription(java.lang.String)
	 */
	public void setDescription(String description) {
		// no need to be implemented
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setGroupVisualization(net.groupme.model.GroupVisualization)
	 */
	public void setGroupVisualization(GroupVisualization visualization)
			throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_VISUALIZATIONID + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter(
				"visualizationID", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = visualization.getId();
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setHeight(int)
	 */
	public void setHeight(int height) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_HEIGHT + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("height", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = height;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#setLabel(java.lang.String)
	 */
	public void setLabel(String label) {
		// no need to be implemented
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setPositionX(int)
	 */
	public void setPositionX(int posX) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_POSITIONX + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("posX", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = posX;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setPositionY(int)
	 */
	public void setPositionY(int posY) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_POSITIONY + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("posY", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = posY;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setRenderer(java.lang.String)
	 */
	public void setRenderer(String renderer) {
		updateField(RESOURCEVISUALIZATION_RENDERER, renderer, Types.VARCHAR);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setResource(net.groupme.model.Resource)
	 */
	public void setResource(Resource resource) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_RESOURCEID + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("resourceID", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = resource.getId();
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setWidth(int)
	 */
	public void setWidth(int width) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_WIDTH + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("width", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = width;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.ResourceVisualization#setWidth(int)
	 */
	public void setZAxis(int zAxis) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + TABLE_RESOURCEVISUALIZATION + " SET " + RESOURCEVISUALIZATION_POSITIONZ + " = ? WHERE " + RESOURCEVISUALIZATION_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("zaxis", Types.INTEGER)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = zAxis;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}
	
	/**
	 * Small helper function which updates a field of this Statement.
	 * @param fieldName the attribute name within the Statement table
	 * @param value the new value
	 * @return returns <code>true</code> if the update was successfully, otherwise <code>false</code>
	 */
	private boolean updateField(String fieldName, String value, int type){
		try {
			SQLUpdateUtility.updateSingleFieldByID(ds, TABLE_RESOURCEVISUALIZATION, RESOURCEVISUALIZATION_ID, id, fieldName, value, type);
		} catch (UpdateFailedException e) {
			log.error("Error on update " + e);
			e.printStackTrace();
			return false;
		}
		return true;
	}
}
